# * author:LHY
#*date:2022-1-7
#第一版第一阶段

from gurobipy import *
'''
#*date: 2022-1-8
时间片的边界和真实时间&时间片的对应关系的处理
输入时把timepiece+1；引入multipleNum变量处理
'''
'''
order的数据结构需要修改
'''
class Data:
    timepiece = 0   #实际代表时刻 从0时刻开始 相当于区间加1
    customerNum = 0
    multipleNum = 1 #对应转换关系 需要手动计算在txt文件中读取
    orderNum = []  # 顾客编号
    orderTime = []  #订单到来时间
    prepareTime = []    #需要的拣货时间
    orderDemand = []    #需求量
    serviceTime = []    #服务时间
    timeMatrix = [[]]   #记录订单到达时间的区间 定义w(i_s)
    #timeMinus = [[]]
    timePara = [[]]
    timeNum = []    #每一时间切片前的订单数量 定义S(t_s)
class customer:
    Num = []
    cor_X = []
    cor_Y = []

def readData(data, path):
    f = open(path, 'r')
    lines = f.readlines()
    data.customerNum = len(lines) - 8
    count = 0
    #print(len(lines))
    for line in lines:
        count = count + 1
        if count == 4:
            line = line[:-1].strip()
            str = re.split(r" +", line)
            data.timepiece=int(str[0])
            data.multipleNum = int(str[1])
        if count >= 9 and count < 9 + data.customerNum:
            line = line[:-1]
            str = re.split(r" +",line)
            data.orderNum.append(int(str[1]))

            data.orderTime.append(float(str[2]))
            data.prepareTime.append(float(str[3]))
            data.orderDemand.append(float(str[4]))
            data.serviceTime.append(float(str[5]))
    #timepiece s时刻是否能够配送
    data.timeMatrix = [([0] * data.timepiece) for p in range(data.customerNum)]    #初始化，防止浅拷贝 timepiece列 customerNum行
    for i in range(0,data.customerNum):
        for j in range(0, data.timepiece):
            if (data.orderTime[i] + data.prepareTime[i])/data.multipleNum < j :
                data.timeMatrix[i][j] = 1
    #data.timeMinus = [([0] * customerNum) for p in range(timepiece)]
    # for i in range(0,customerNum):
    #     for j in range(0, timepiece):
    #         data.timeMinus[i][j] = j - data.orderTime[i] - data.prepareTime[i]
    data.timePara = [([0] * data.timepiece) for p in range(data.timepiece)]
    for i in range(0,data.timepiece-1):
        for j in range(i+1, data.timepiece):
            for k in range(0,data.customerNum):
                data.timePara[i][j] += (data.timeMatrix[k][j] - data.timeMatrix[k][i]) * (j * data.multipleNum - data.orderTime[k] - data.prepareTime[k])

    data.timeNum = [0] * data.timepiece
    for i in range(1, data.timepiece):
        for k in range(0,data.customerNum):
            data.timeNum[i] += data.timeMatrix[k][i]

    return data
data = Data()
path = 'c101.txt'

###customer需要改


readData(data,path)
BigM = 1e6
I = 10
lam = 0.04
for ii in range(0, data.customerNum):
    for jj in range(0, data.timepiece):
        print(str(data.timeMatrix[ii][jj]),end=' ')
    print('\n')
# for ii in range(data.timepiece):
#     print(str(data.timeNum[ii]),end=' ')

model = Model('firststage')

y = {}
#定义决策变量
for i in range(data.timepiece):
    for j in range(data.timepiece):
       if(i != j):
            name = 'y' + str(i) + '_' + str(j)
            y[i,j] = model.addVar(0
                                  ,1
                                  ,vtype = GRB.BINARY
                                  ,name = name)
model.update()
obj = LinExpr(0)
for r in range(data.timepiece-1):
    for s in range(r+1,data.timepiece):
        obj.addTerms(data.timePara[r][s],y[r,s])
model.setObjective(obj, GRB.MINIMIZE)
#相邻间隔最少订单数
for r in range(data.timepiece-1):
    for s in range(r+1,data.timepiece):
        model.addConstr(data.timeNum[s] - data.timeNum[r] >= I - BigM * (1 - y[r,s]),name='cons1')
#最少趟次约束
lhs = LinExpr(0)
for r in range(data.timepiece):
    for s in range(r+1,data.timepiece):
        lhs.addTerms(1,y[r,s])
model.addConstr(lhs >= data.timeNum[data.timepiece-1] * lam,name = 'cons2')
#起始区间流平衡
lhs = LinExpr(0)
for j in range(1,data.timepiece):
    lhs.addTerms(1,y[0,j])
model.addConstr(lhs == 1, name='flow_conservation_0')
#中间时间段的流平衡
for h in range(1,data.timepiece-1):
    expr1 = LinExpr(0)
    expr2 = LinExpr(0)
    for i in range(h-1):
        expr1.addTerms(1,y[i,h])
    for j in range(h+1,data.timepiece):
        expr2.addTerms(1,y[h,j])
    model.addConstr(expr1==expr2,name='flow_conservation_'+str(h))
    expr1.clear()
    expr2.clear()
#终止区间流平衡
lhs = LinExpr(0)
for j in range(0,data.timepiece-2):
    lhs.addTerms(1,y[j,data.timepiece-1])
model.addConstr(lhs == 1, name='flow_conservation_last')
# 导出模型
model.write('Timepiece1.lp')
# 求解
model.optimize()

# 打印结果
print("\n\n-----optimal value-----")
print(model.ObjVal)

for key in y.keys():
    if (y[key].x>0):
        print(y[key].VarName + ' = ', y[key].x)
